
import { EventTarget } from "cc";
import { GameStorage } from "./GameStorage";
import { GameManager, IUpdatable, regGameManager } from "./GameManager";

export abstract class BaseGame {

    eventTarget = new EventTarget();
    elapsedTime = 0
    lastUpdateTime = 0
    timeScale = 1;
    isFirstGame = true

    public get frame(): number { return this._frame; }
    protected _frame: number = 0;
    protected _managers: GameManager[] = [];
    protected _managersMap = new Map<Object, GameManager>()
    protected _updates: IUpdatable[] = [];
    protected _initFinishedManagers: any[] = [];

    constructor() {
        this.isFirstGame = !!GameStorage.getItem(`${GameStorage.keyPrefix}_isPlayedOnce`)
        GameStorage.setItem(`${GameStorage.keyPrefix}_isPlayedOnce`, "1")
    }
    public mgr<T extends GameManager>(manager: (new () => T)) {
        return this._managersMap.get(manager) as T
    }

    public async initialize(onProgress?: (finished: number, total: number, item: GameManager) => void): Promise<void> {
        this._initFinishedManagers = []
        this._addManagers()

        const maxOrder = this._managers[this._managers.length - 1].constructor['config'].initOrder
        /**每个initOrder的manager列表 */
        const managerArrs: GameManager[][] = []
        for (let order = 0; order <= maxOrder; order++) {
            managerArrs.push([])
        }

        for (let i = 0; i < this._managers.length; i++) {
            const mgr = this._managers[i]
            const initOrder = mgr.constructor['config'].initOrder
            managerArrs[initOrder].push(mgr)
        }

        for (let order = 0; order < managerArrs.length; order++) {
            const managerArr = managerArrs[order];
            const initingArr: Promise<void>[] = []
            for (let i = 0; i < managerArr.length; i++) {
                const mgr = managerArr[i];
                if (mgr.initialize) {
                    let initPromise = mgr.initialize().then(() => {
                        this._initFinishedManagers.push(mgr)
                        onProgress && onProgress(this._initFinishedManagers.length, this._managers.length, mgr)
                    })
                    initingArr.push(initPromise)
                }
            }
            await Promise.all(initingArr)
        }

        this.onInitComplete()
    }

    public destroy(): void {
        for (let _i = this._managers.length - 1; _i >= 0; _i--) {
            this._managers[_i].constructor['_instance'] = null
            this._managers[_i].destroy && (this._managers[_i].destroy());
        }
        this._managers.length = 0;
        this._updates.length = 0;
        this._managersMap.clear();
    }

    public update(dt: number): void {
        if (!this.isInitComplete()) {
            return;
        }

        //检查是否初始化完成，初始化完成后，才能开始系统的Tick
        this._frame++;
        this.elapsedTime += dt
        this.lastUpdateTime = this.elapsedTime
        for (let _i = 0; _i < this._updates.length; _i++) {
            this._updates[_i].update(dt);
        }
    }

    public addManager(mgr: GameManager): GameManager {
        mgr.game = this;
        this._managers.push(mgr);
        this._managersMap.set(mgr.constructor, mgr);
        if ("update" in mgr) {
            this._updates.push(mgr as unknown as IUpdatable);
        }

        return mgr;
    }

    /**添加通过装饰器注册的管理器 */
    private _addManagers() {
        const clzArr: any[] = (regGameManager as any).clzArr
        clzArr.sort((a, b) => {
            return a.config.initOrder - b.config.initOrder
        })
        console.log(clzArr);

        for (let index = 0; index < clzArr.length; index++) {
            const clz = clzArr[index];
            this.addManager(clz.instance())
        }
    }

    //检查系统初始化是否完成
    isInitComplete(): boolean {
        return this._managers.length != 0 && this._initFinishedManagers.length == this._managers.length
    }

    onInitComplete() { }
}